home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / share / pyshared / PIL / IptcImagePlugin.py < prev    next >
Text File  |  2006-12-03  |  7KB  |  281 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id: IptcImagePlugin.py 2813 2006-10-07 10:11:35Z fredrik $
  4. #
  5. # IPTC/NAA file handling
  6. #
  7. # history:
  8. # 1995-10-01 fl   Created
  9. # 1998-03-09 fl   Cleaned up and added to PIL
  10. # 2002-06-18 fl   Added getiptcinfo helper
  11. #
  12. # Copyright (c) Secret Labs AB 1997-2002.
  13. # Copyright (c) Fredrik Lundh 1995.
  14. #
  15. # See the README file for information on usage and redistribution.
  16. #
  17.  
  18.  
  19. __version__ = "0.3"
  20.  
  21.  
  22. import Image, ImageFile
  23. import os, tempfile
  24.  
  25.  
  26. COMPRESSION = {
  27.     1: "raw",
  28.     5: "jpeg"
  29. }
  30.  
  31. PAD = chr(0) * 4
  32.  
  33. #
  34. # Helpers
  35.  
  36. def i16(c):
  37.     return ord(c[1]) + (ord(c[0])<<8)
  38.  
  39. def i32(c):
  40.     return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
  41.  
  42. def i(c):
  43.     return i32((PAD + c)[-4:])
  44.  
  45. def dump(c):
  46.     for i in c:
  47.         print "%02x" % ord(i),
  48.     print
  49.  
  50. ##
  51. # Image plugin for IPTC/NAA datastreams.  To read IPTC/NAA fields
  52. # from TIFF and JPEG files, use the <b>getiptcinfo</b> function.
  53.  
  54. class IptcImageFile(ImageFile.ImageFile):
  55.  
  56.     format = "IPTC"
  57.     format_description = "IPTC/NAA"
  58.  
  59.     def getint(self, key):
  60.         return i(self.info[key])
  61.  
  62.     def field(self):
  63.         #
  64.         # get a IPTC field header
  65.         s = self.fp.read(5)
  66.         if not len(s):
  67.             return None, 0
  68.  
  69.         tag = ord(s[1]), ord(s[2])
  70.  
  71.         # syntax
  72.         if ord(s[0]) != 0x1C or tag[0] < 1 or tag[0] > 9:
  73.             raise SyntaxError, "invalid IPTC/NAA file"
  74.  
  75.         # field size
  76.         size = ord(s[3])
  77.         if size > 132:
  78.             raise IOError, "illegal field length in IPTC/NAA file"
  79.         elif size == 128:
  80.             size = 0
  81.         elif size > 128:
  82.             size = i(self.fp.read(size-128))
  83.         else:
  84.             size = i16(s[3:])
  85.  
  86.         return tag, size
  87.  
  88.     def _is_raw(self, offset, size):
  89.         #
  90.         # check if the file can be mapped
  91.  
  92.         # DISABLED: the following only slows things down...
  93.         return 0
  94.  
  95.         self.fp.seek(offset)
  96.         t, sz = self.field()
  97.         if sz != size[0]:
  98.             return 0
  99.         y = 1
  100.         while 1:
  101.             self.fp.seek(sz, 1)
  102.             t, s = self.field()
  103.             if t != (8, 10):
  104.                 break
  105.             if s != sz:
  106.                 return 0
  107.             y = y + 1
  108.         return y == size[1]
  109.  
  110.     def _open(self):
  111.  
  112.         # load descriptive fields
  113.         while 1:
  114.             offset = self.fp.tell()
  115.             tag, size = self.field()
  116.             if not tag or tag == (8,10):
  117.                 break
  118.             if size:
  119.                 self.info[tag] = self.fp.read(size)
  120.             else:
  121.                 self.info[tag] = None
  122.             # print tag, self.info[tag]
  123.  
  124.         # mode
  125.         layers = ord(self.info[(3,60)][0])
  126.         component = ord(self.info[(3,60)][1])
  127.         if self.info.has_key((3,65)):
  128.             id = ord(self.info[(3,65)][0])-1
  129.         else:
  130.             id = 0
  131.         if layers == 1 and not component:
  132.             self.mode = "L"
  133.         elif layers == 3 and component:
  134.             self.mode = "RGB"[id]
  135.         elif layers == 4 and component:
  136.             self.mode = "CMYK"[id]
  137.  
  138.         # size
  139.         self.size = self.getint((3,20)), self.getint((3,30))
  140.  
  141.         # compression
  142.         try:
  143.             compression = COMPRESSION[self.getint((3,120))]
  144.         except KeyError:
  145.             raise IOError, "Unknown IPTC image compression"
  146.  
  147.         # tile
  148.         if tag == (8,10):
  149.             if compression == "raw" and self._is_raw(offset, self.size):
  150.                 self.tile = [(compression, (offset, size + 5, -1),
  151.                              (0, 0, self.size[0], self.size[1]))]
  152.             else:
  153.                 self.tile = [("iptc", (compression, offset),
  154.                              (0, 0, self.size[0], self.size[1]))]
  155.  
  156.     def load(self):
  157.  
  158.         if len(self.tile) != 1 or self.tile[0][0] != "iptc":
  159.             return ImageFile.ImageFile.load(self)
  160.  
  161.         type, tile, box = self.tile[0]
  162.  
  163.         encoding, offset = tile
  164.  
  165.         self.fp.seek(offset)
  166.  
  167.         # Copy image data to temporary file
  168.         outfile = tempfile.mktemp()
  169.         o = open(outfile, "wb")
  170.         if encoding == "raw":
  171.             # To simplify access to the extracted file,
  172.             # prepend a PPM header
  173.             o.write("P5\n%d %d\n255\n" % self.size)
  174.         while 1:
  175.             type, size = self.field()
  176.             if type != (8, 10):
  177.                 break
  178.             while size > 0:
  179.                 s = self.fp.read(min(size, 8192))
  180.                 if not s:
  181.                     break
  182.                 o.write(s)
  183.                 size = size - len(s)
  184.         o.close()
  185.  
  186.         try:
  187.             try:
  188.                 # fast
  189.                 self.im = Image.core.open_ppm(outfile)
  190.             except:
  191.                 # slightly slower
  192.                 im = Image.open(outfile)
  193.                 im.load()
  194.                 self.im = im.im
  195.         finally:
  196.             try: os.unlink(outfile)
  197.             except: pass
  198.  
  199.  
  200. Image.register_open("IPTC", IptcImageFile)
  201.  
  202. Image.register_extension("IPTC", ".iim")
  203.  
  204. ##
  205. # Get IPTC information from TIFF, JPEG, or IPTC file.
  206. #
  207. # @param im An image containing IPTC data.
  208. # @return A dictionary containing IPTC information, or None if
  209. #     no IPTC information block was found.
  210.  
  211. def getiptcinfo(im):
  212.  
  213.     import TiffImagePlugin, JpegImagePlugin
  214.     import StringIO
  215.  
  216.     data = None
  217.  
  218.     if isinstance(im, IptcImageFile):
  219.         # return info dictionary right away
  220.         return im.info
  221.  
  222.     elif isinstance(im, JpegImagePlugin.JpegImageFile):
  223.         # extract the IPTC/NAA resource
  224.         try:
  225.             app = im.app["APP13"]
  226.             if app[:14] == "Photoshop 3.0\x00":
  227.                 app = app[14:]
  228.                 # parse the image resource block
  229.                 offset = 0
  230.                 while app[offset:offset+4] == "8BIM":
  231.                     offset = offset + 4
  232.                     # resource code
  233.                     code = JpegImagePlugin.i16(app, offset)
  234.                     offset = offset + 2
  235.                     # resource name (usually empty)
  236.                     name_len = ord(app[offset])
  237.                     name = app[offset+1:offset+1+name_len]
  238.                     offset = 1 + offset + name_len
  239.                     if offset & 1:
  240.                         offset = offset + 1
  241.                     # resource data block
  242.                     size = JpegImagePlugin.i32(app, offset)
  243.                     offset = offset + 4
  244.                     if code == 0x0404:
  245.                         # 0x0404 contains IPTC/NAA data
  246.                         data = app[offset:offset+size]
  247.                         break
  248.                     offset = offset + size
  249.                     if offset & 1:
  250.                         offset = offset + 1
  251.         except (AttributeError, KeyError):
  252.             pass
  253.  
  254.     elif isinstance(im, TiffImagePlugin.TiffImageFile):
  255.         # get raw data from the IPTC/NAA tag (PhotoShop tags the data
  256.         # as 4-byte integers, so we cannot use the get method...)
  257.         try:
  258.             type, data = im.tag.tagdata[TiffImagePlugin.IPTC_NAA_CHUNK]
  259.         except (AttributeError, KeyError):
  260.             pass
  261.  
  262.     if data is None:
  263.         return None # no properties
  264.  
  265.     # create an IptcImagePlugin object without initializing it
  266.     class FakeImage:
  267.         pass
  268.     im = FakeImage()
  269.     im.__class__ = IptcImageFile
  270.  
  271.     # parse the IPTC information chunk
  272.     im.info = {}
  273.     im.fp = StringIO.StringIO(data)
  274.  
  275.     try:
  276.         im._open()
  277.     except (IndexError, KeyError):
  278.         pass # expected failure
  279.  
  280.     return im.info
  281.